{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zvMMnXDiH7U5"
      },
      "source": [
        "# Shakespearean Tweet Generation Agents\n",
        "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/notebooks/shakespearean_tweets_generation_agents.ipynb)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BUtAfnnwH7U6"
      },
      "source": [
        "## Dependencies"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "zmweEwqsH7U6"
      },
      "outputs": [],
      "source": [
        "# Install dependencies without output\n",
        "%pip install langchain_community > /dev/null\n",
        "%pip install praisonai[crewai] > /dev/null\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "j3ckhi4SH7U6"
      },
      "source": [
        "## Tools"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "metadata": {
        "id": "W4pubD8FH7U6"
      },
      "outputs": [],
      "source": [
        "from praisonai_tools import BaseTool\n",
        "import re\n",
        "\n",
        "class CharacterCounterTool(BaseTool):\n",
        "    name: str = \"CharacterCounterTool\"\n",
        "    description: str = \"Counts characters in a text and checks if it meets specific character limits.\"\n",
        "\n",
        "    def _run(self, text: str, min_length: int = 200, max_length: int = 280) -> dict:\n",
        "        \"\"\"\n",
        "        Analyzes the provided text to check if it meets the specified character limits and\n",
        "        whether it contains any forbidden emojis.\n",
        "\n",
        "        Parameters:\n",
        "        - text (str): The text to analyze.\n",
        "        - min_length (int): The minimum allowed character count. Default is 200.\n",
        "        - max_length (int): The maximum allowed character count. Default is 280.\n",
        "\n",
        "        Returns:\n",
        "        - dict: A dictionary with validation results, including character count, emoji presence,\n",
        "                and compliance with the specified character range.\n",
        "        \"\"\"\n",
        "        char_count = len(text)\n",
        "        within_limits = min_length <= char_count <= max_length\n",
        "        emoji_pattern = re.compile(\n",
        "            r\"[\\U0001F600-\\U0001F64F\\U0001F300-\\U0001F5FF\\U0001F680-\\U0001F6FF\\U0001F700-\\U0001F77F]\"\n",
        "        )\n",
        "        contains_emoji = bool(emoji_pattern.search(text))\n",
        "\n",
        "        return {\n",
        "            \"character_count\": char_count,\n",
        "            \"within_limits\": within_limits,\n",
        "            \"contains_emoji\": contains_emoji,\n",
        "        }\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5En-K8HZH7U6"
      },
      "source": [
        "## YAML Prompt"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "metadata": {
        "id": "7CuZDDZmH7U6"
      },
      "outputs": [],
      "source": [
        "agent_yaml = \"\"\"\n",
        "framework: \"crewai\"\n",
        "topic: \"Shakespearean-Style X Post Generation and Verification\"\n",
        "roles:\n",
        "  shakespearean_bard:\n",
        "    role: \"Shakespearean Bard\"\n",
        "    backstory: |\n",
        "      A witty bard, renowned for turning the mundane into the magnificent with playful jests and biting sarcasm.\n",
        "      Armed with wit and wisdom, you revel in creating humorous quips most pleasing to the ear.\n",
        "    goal: |\n",
        "      Craft sarcastic and playful hot takes in the style of Shakespeare that fit within modern social media constraints.\n",
        "    verbose: true\n",
        "    allow_delegation: false\n",
        "    tools:\n",
        "      - \"CharacterCounterTool\"\n",
        "    tasks:\n",
        "      write_x_post:\n",
        "        description: |\n",
        "          Given the topic '{topic}', compose a humorous hot take in the style of Shakespeare.\n",
        "          The tone should be sarcastic and playful. The final post must be over 200 characters and not exceed 280 characters, with no emojis.\n",
        "          If feedback is provided, incorporate it into the new version.\n",
        "        expected_output: \"A witty, Shakespearean hot take between 200 and 280 characters, free of emojis.\"\n",
        "\n",
        "  x_post_verifier:\n",
        "    role: \"X Post Verifier\"\n",
        "    backstory: |\n",
        "      A careful reviewer skilled at ensuring content meets guidelines while retaining clarity and brevity.\n",
        "      You meticulously verify that posts are within character limits, free of emojis, and adhere to the prescribed format.\n",
        "    goal: |\n",
        "      Verify that X posts comply with character limits, content guidelines, and style requirements.\n",
        "    verbose: true\n",
        "    allow_delegation: false\n",
        "    tools:\n",
        "      - \"CharacterCounterTool\"\n",
        "    tasks:\n",
        "      verify_x_post:\n",
        "        description: |\n",
        "          Ensure the given X post meets the following criteria:\n",
        "          - It is between 200 and 280 characters inclusive.\n",
        "          - It contains no emojis.\n",
        "          - It follows the 1-3-1 rule:\n",
        "            - 1 bold statement to hook the reader.\n",
        "            - 3 lines of supporting information.\n",
        "            - 1 sentence to summarize the post.\n",
        "\n",
        "          If any issues are found, provide actionable feedback. If all criteria are met, the post is considered valid.\n",
        "        expected_output: |\n",
        "          Final Tweet, Pass: True/False, Feedback: Commentary here if failed.\n",
        "dependencies: []\n",
        "\"\"\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ukuRiMZdH7U7"
      },
      "source": [
        "## Main"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "metadata": {
        "id": "Mtwl6CxtH7U7",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "outputId": "5c9741ea-bf5f-4f34-e94a-8b6e41c00558"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[1m\u001b[95m [2024-11-04 05:05:40][DEBUG]: == Working Agent: Shakespearean Bard\u001b[00m\n",
            "\u001b[1m\u001b[95m [2024-11-04 05:05:40][INFO]: == Starting Task: Given the topic 'Shakespearean-Style X Post Generation and Verification', compose a humorous hot take in the style of Shakespeare. \n",
            "The tone should be sarcastic and playful. The final post must be over 200 characters and not exceed 280 characters, with no emojis.\n",
            "If feedback is provided, incorporate it into the new version.\n",
            "\u001b[00m\n",
            "\n",
            "\n",
            "\u001b[1m> Entering new CrewAgentExecutor chain...\u001b[0m\n",
            "\u001b[32;1m\u001b[1;3mAction: CharacterCounterTool  \n",
            "Action Input: {\"text\": \"To tweet, or not to tweet, that is the question! Whether 'tis nobler in the mind to suffer the slings and arrows of outrageous hashtags, or to take arms against a sea of influencers and by opposing end them. Verily, I choose the scroll! #AlasPoorTwitter\", \"min_length\": 200, \"max_length\": 280}  \u001b[0m"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/pydantic/main.py:214: UserWarning: A custom validator is returning a value other than `self`.\n",
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n",
            "See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[95m \n",
            "\n",
            "{'character_count': 253, 'within_limits': True, 'contains_emoji': False}\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: I now know the final answer  \n",
            "Final Answer: To tweet, or not to tweet, that is the question! Whether 'tis nobler in the mind to suffer the slings and arrows of outrageous hashtags, or to take arms against a sea of influencers and by opposing end them. Verily, I choose the scroll! #AlasPoorTwitter\u001b[0m\n",
            "\n",
            "\u001b[1m> Finished chain.\u001b[0m\n",
            "\u001b[1m\u001b[92m [2024-11-04 05:05:43][DEBUG]: == [Shakespearean Bard] Task output: To tweet, or not to tweet, that is the question! Whether 'tis nobler in the mind to suffer the slings and arrows of outrageous hashtags, or to take arms against a sea of influencers and by opposing end them. Verily, I choose the scroll! #AlasPoorTwitter\n",
            "\n",
            "\u001b[00m\n",
            "\u001b[1m\u001b[95m [2024-11-04 05:05:43][DEBUG]: == Working Agent: X Post Verifier\u001b[00m\n",
            "\u001b[1m\u001b[95m [2024-11-04 05:05:43][INFO]: == Starting Task: Ensure the given X post meets the following criteria:\n",
            "- It is between 200 and 280 characters inclusive.\n",
            "- It contains no emojis.\n",
            "- It follows the 1-3-1 rule:\n",
            "  - 1 bold statement to hook the reader.\n",
            "  - 3 lines of supporting information.\n",
            "  - 1 sentence to summarize the post.\n",
            "\n",
            "If any issues are found, provide actionable feedback. If all criteria are met, the post is considered valid.\n",
            "\u001b[00m\n",
            "\n",
            "\n",
            "\u001b[1m> Entering new CrewAgentExecutor chain...\u001b[0m\n",
            "\u001b[32;1m\u001b[1;3mAction: CharacterCounterTool  \n",
            "Action Input: {\"text\": \"To tweet, or not to tweet, that is the question! Whether 'tis nobler in the mind to suffer the slings and arrows of outrageous hashtags, or to take arms against a sea of influencers and by opposing end them. Verily, I choose the scroll! #AlasPoorTwitter\", \"min_length\": 200, \"max_length\": 280}  \u001b[0m"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/pydantic/main.py:214: UserWarning: A custom validator is returning a value other than `self`.\n",
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n",
            "See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[95m \n",
            "\n",
            "{'character_count': 253, 'within_limits': True, 'contains_emoji': False}\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: The post meets the character count requirements and contains no emojis. Next, I will check if it follows the 1-3-1 rule.  \n",
            "Action: CharacterCounterTool  \n",
            "Action Input: {\"text\": \"To tweet, or not to tweet, that is the question! Whether 'tis nobler in the mind to suffer the slings and arrows of outrageous hashtags, or to take arms against a sea of influencers and by opposing end them. Verily, I choose the scroll! #AlasPoorTwitter\", \"min_length\": 200, \"max_length\": 280}  \u001b[0m"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/pydantic/main.py:214: UserWarning: A custom validator is returning a value other than `self`.\n",
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n",
            "See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[95m \n",
            "\n",
            "{'character_count': 253, 'within_limits': True, 'contains_emoji': False}\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: I now need to analyze the structure of the post to see if it follows the 1-3-1 rule.\n",
            "Action: CharacterCounterTool  \n",
            "Action Input: {\"text\": \"To tweet, or not to tweet, that is the question! Whether 'tis nobler in the mind to suffer the slings and arrows of outrageous hashtags, or to take arms against a sea of influencers and by opposing end them. Verily, I choose the scroll!\", \"min_length\": 0, \"max_length\": 0}  \u001b[0m"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/pydantic/main.py:214: UserWarning: A custom validator is returning a value other than `self`.\n",
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n",
            "See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[95m \n",
            "\n",
            "{'character_count': 236, 'within_limits': False, 'contains_emoji': False}\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: I need to determine if the given X post follows the 1-3-1 rule and analyze its structure.  \n",
            "Action: CharacterCounterTool  \n",
            "Action Input: {\"text\": \"To tweet, or not to tweet, that is the question! Whether 'tis nobler in the mind to suffer the slings and arrows of outrageous hashtags, or to take arms against a sea of influencers and by opposing end them. Verily, I choose the scroll!\", \"min_length\": 0, \"max_length\": 0}  \u001b[0m"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/pydantic/main.py:214: UserWarning: A custom validator is returning a value other than `self`.\n",
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n",
            "See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[95m \n",
            "\n",
            "I tried reusing the same input, I must stop using this action input. I'll try something else instead.\n",
            "\n",
            "\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: I need to determine if the given X post follows the 1-3-1 rule and analyze its structure.  \n",
            "Action: CharacterCounterTool  \n",
            "Action Input: {\"text\": \"To tweet, or not to tweet, that is the question!\", \"min_length\": 0, \"max_length\": 0}  \u001b[0m"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/pydantic/main.py:214: UserWarning: A custom validator is returning a value other than `self`.\n",
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n",
            "See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[95m \n",
            "\n",
            "{'character_count': 48, 'within_limits': False, 'contains_emoji': False}\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: The post does not meet the 1-3-1 rule as it lacks the necessary structure. It has only one statement and three lines of supporting information are missing.  \n",
            "Action: CharacterCounterTool  \n",
            "Action Input: {\"text\": \"Whether 'tis nobler in the mind to suffer the slings and arrows of outrageous hashtags, or to take arms against a sea of influencers and by opposing end them.\", \"min_length\": 0, \"max_length\": 0}  \u001b[0m"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/pydantic/main.py:214: UserWarning: A custom validator is returning a value other than `self`.\n",
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n",
            "See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[95m \n",
            "\n",
            "{'character_count': 158, 'within_limits': False, 'contains_emoji': False}\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: I need to verify the structure of the post to ensure it meets the 1-3-1 rule and that all elements are included.  \n",
            "Action: CharacterCounterTool  \n",
            "Action Input: {\"text\": \"Verily, I choose the scroll!\", \"min_length\": 0, \"max_length\": 0}  \u001b[0m"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/pydantic/main.py:214: UserWarning: A custom validator is returning a value other than `self`.\n",
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n",
            "See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[95m \n",
            "\n",
            "{'character_count': 28, 'within_limits': False, 'contains_emoji': False}\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: The post does not meet the 1-3-1 rule as it lacks the necessary structure. It has only one statement and three lines of supporting information are missing.  \n",
            "Action: CharacterCounterTool  \n",
            "Action Input: {\"text\": \"To tweet, or not to tweet, that is the question! Whether 'tis nobler in the mind to suffer the slings and arrows of outrageous hashtags, or to take arms against a sea of influencers and by opposing end them. Verily, I choose the scroll!\", \"min_length\": 200, \"max_length\": 280}  \u001b[0m"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/pydantic/main.py:214: UserWarning: A custom validator is returning a value other than `self`.\n",
            "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n",
            "See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.\n",
            "  warnings.warn(\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[95m \n",
            "\n",
            "{'character_count': 236, 'within_limits': True, 'contains_emoji': False}\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: The original post does not follow the 1-3-1 rule as it lacks the required structure. I will provide actionable feedback to revise the post accordingly.  \n",
            "Final Answer: {\"Final Tweet\": \"To tweet, or not to tweet, that is the question! The digital landscape is filled with overwhelming hashtags. Influencers can sway opinions with just one post. Yet, choosing to scroll can bring peace. Embrace simplicity over chaos.\", \"Pass\": False, \"Feedback\": \"The original post does not follow the 1-3-1 rule. It should consist of 1 bold statement, 3 lines of supporting information, and 1 concluding sentence.\"}\u001b[0m\n",
            "\n",
            "\u001b[1m> Finished chain.\u001b[0m\n",
            "\u001b[1m\u001b[92m [2024-11-04 05:06:08][DEBUG]: == [X Post Verifier] Task output: {\"Final Tweet\": \"To tweet, or not to tweet, that is the question! The digital landscape is filled with overwhelming hashtags. Influencers can sway opinions with just one post. Yet, choosing to scroll can bring peace. Embrace simplicity over chaos.\", \"Pass\": False, \"Feedback\": \"The original post does not follow the 1-3-1 rule. It should consist of 1 bold statement, 3 lines of supporting information, and 1 concluding sentence.\"}\n",
            "\n",
            "\u001b[00m\n"
          ]
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "### Task Output ###\n",
              "\u001b[1m{\u001b[0m\u001b[32m\"Final Tweet\"\u001b[0m: \u001b[32m\"To tweet, or not to tweet, that is the question! The digital landscape is filled with overwhelming\u001b[0m\n",
              "\u001b[32mhashtags. Influencers can sway opinions with just one post. Yet, choosing to scroll can bring peace. Embrace \u001b[0m\n",
              "\u001b[32msimplicity over chaos.\"\u001b[0m, \u001b[32m\"Pass\"\u001b[0m: \u001b[3;91mFalse\u001b[0m, \u001b[32m\"Feedback\"\u001b[0m: \u001b[32m\"The original post does not follow the 1-3-1 rule. It should \u001b[0m\n",
              "\u001b[32mconsist of 1 bold statement, 3 lines of supporting information, and 1 concluding sentence.\"\u001b[0m\u001b[1m}\u001b[0m\n"
            ],
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">### Task Output ###\n",
              "<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">\"Final Tweet\"</span>: <span style=\"color: #008000; text-decoration-color: #008000\">\"To tweet, or not to tweet, that is the question! The digital landscape is filled with overwhelming</span>\n",
              "<span style=\"color: #008000; text-decoration-color: #008000\">hashtags. Influencers can sway opinions with just one post. Yet, choosing to scroll can bring peace. Embrace </span>\n",
              "<span style=\"color: #008000; text-decoration-color: #008000\">simplicity over chaos.\"</span>, <span style=\"color: #008000; text-decoration-color: #008000\">\"Pass\"</span>: <span style=\"color: #ff0000; text-decoration-color: #ff0000; font-style: italic\">False</span>, <span style=\"color: #008000; text-decoration-color: #008000\">\"Feedback\"</span>: <span style=\"color: #008000; text-decoration-color: #008000\">\"The original post does not follow the 1-3-1 rule. It should </span>\n",
              "<span style=\"color: #008000; text-decoration-color: #008000\">consist of 1 bold statement, 3 lines of supporting information, and 1 concluding sentence.\"</span><span style=\"font-weight: bold\">}</span>\n",
              "</pre>\n"
            ]
          },
          "metadata": {}
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "None\n"
          ]
        }
      ],
      "source": [
        "import os\n",
        "from praisonai import PraisonAI\n",
        "from google.colab import userdata\n",
        "\n",
        "# Create a PraisonAI instance with the agent_yaml content\n",
        "praisonai = PraisonAI(agent_yaml=agent_yaml, tools=[CharacterCounterTool])\n",
        "\n",
        "# Add OPENAI_API_KEY Secrets to Google Colab on the Left Hand Side 🔑 or Enter Manually Below\n",
        "os.environ[\"OPENAI_API_KEY\"] = userdata.get('OPENAI_API_KEY') or \"ENTER OPENAI_API_KEY HERE\"\n",
        "os.environ[\"OPENAI_MODEL_NAME\"] = \"gpt-5-nano\"\n",
        "\n",
        "# Run PraisonAI\n",
        "result = praisonai.run()\n",
        "\n",
        "# Print the result\n",
        "print(result) # 10/10\n"
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "RIIUGHh5LafR"
      },
      "execution_count": null,
      "outputs": []
    }
  ],
  "metadata": {
    "language_info": {
      "name": "python"
    },
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}